
require('MicroPather')

--
-- Map representation
--
local map = {}
map[1] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
map[2] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
map[3] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
map[4] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
map[5] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
map[6] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
map[7] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
map[8] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
map[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
map[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }

function I2D ( n )
  local x = n % #map[1]
  local y = ( n - x ) / #map[1]
  return x + 1, y + 1
end

function I1D ( x, y )
  return ( y - 1 ) * #map[1] + ( x - 1 )
end

tile = 40


--display:create ( "MicroPather Demo", 440, 440, 32, true )

local dm = DisplayMode ( )
dm.width = #map[1] * tile
dm.height = #map * tile
dm.depth = 32
dm.windowed = true
display:set_mode ( dm )




--
-- Node graph
--
local pather_map = micropather.Map ( )

pather_map.LeastCostEstimate = function ( self, s, e )
	local sx, sy = I2D ( s )
	local ex, ey = I2D ( e )
	local dx = ex - sx
	local dy = ey - sy
	return math.sqrt ( dx * dx + dy * dy )
end

pather_map.AdjacentCost = function ( self, cell, a )
	local x, y = I2D ( cell )

	if map[y][x] ~= 0 then
		return
	end

	if x < #map[1] and map[y][x + 1] == 0 then
		local sc = micropather.StateCost ()
		sc.state = I1D ( x + 1, y )
		sc.cost  = 1
		table.insert ( a, sc ) -- e 
	end
	if x > 1 and map[y][x - 1] == 0 then
		local sc = micropather.StateCost ( I1D ( x - 1, y ), 1 )
		table.insert ( a, sc ) -- n
	end
	if y < #map and map[y + 1][x] == 0 then
		local sc = micropather.StateCost ( I1D ( x, y + 1 ), 1 )
		table.insert ( a, sc ) -- s
	end
	if y > 1 and map[y - 1][x] == 0 then
		local sc = micropather.StateCost ( I1D ( x, y - 1 ), 1 )
		table.insert ( a, sc ) -- s
	end

end

local pather = micropather.MicroPather ( pather_map )


--
-- Visual representation
--
grid_offset_x = -#map[1] * tile / 2 - tile / 2
grid_offset_y = -#map * tile / 2 - tile / 2

grid = Sprite ( grid_offset_x, grid_offset_y )
display.viewport:add_child ( grid )


function PaintGrid ( )
	grid.canvas:clear ( )

	-- draw cells
	for y, yv in pairs ( map ) do
		for x, xv in pairs ( yv ) do
			grid.canvas:move_to ( x * tile, y * tile )
			grid.canvas:rectangle ( tile - 3, tile - 3 )

			if xv == 1 then
				grid.canvas:set_fill_style ( RED, 1 )
			elseif ( x == 1 and y == 1 ) or ( x == #map[1] and y == #map ) then
				grid.canvas:set_fill_style ( BLUE, 0.5 )
			elseif xv == 0 then
				grid.canvas:set_fill_style ( GRAY, 0.5 )
			end

			grid.canvas:fill ( )
		end
	end
end

--
-- Attempts to solve the graph
--
function Solve ( )
	-- convert start and end cells to indices
	local c1 = I1D ( 1, 1 )
	local c2 = I1D ( #map[1], #map )

	-- attempt to solve
	local cost = 0
	local path = {}
	local ret, cost = pather:Solve ( c1, c2, path, cost )

	if ret == micropather.SOLVED then
		-- draw the path
		for i, v in pairs ( path ) do
			-- convert cell index
			local cx, cy = I2D ( v )

			grid.canvas:move_to ( cx * tile, cy * tile )
			grid.canvas:circle ( 5 )
			grid.canvas:set_fill_style ( LIME, 1 )
			grid.canvas:fill ( )
		end
	elseif ret == micropather.NO_SOLUTION then

	elseif ret == micropather.START_END_SAME then

	end
end

PaintGrid ( )

--
-- Converts mouse coords to grid
--
function ToGrid ( x, y )
	local lx = math.floor ( ( x - grid_offset_x + tile / 2 ) / tile )
	local ly = math.floor ( ( y - grid_offset_y + tile / 2 ) / tile )

	if ly >= 1 and ly <= #map and lx >= 1 and lx <= #map[ly] then
		return lx, ly
	end
	return nil
end

--
-- Edits the map with the mouse
--
mouse.on_press = function ( mouse, button )
	local x, y = ToGrid ( mouse.xaxis, mouse.yaxis )
	if x and y then
		-- edit the map
		if map[y][x] == 0 then
			map[y][x] = 1
		else
			map[y][x] = 0
		end

		-- rebuild the node graph
		pather = micropather.MicroPather ( pather_map )

		-- repaint the map
		PaintGrid ( )

		Solve ( )
	end
end

